package HashTable;

import java.util.Iterator;
import java.util.LinkedList;

public class MyHashTable<K extends Comparable<K>> implements HashInterface {

	private LinkedList<HashObject>[] table;
	private final int a = (int) 100;// (2000 * Math.random());
	private final int b = (int) 200;// (1000 * Math.random());
	private int prime = 101;
	public static final int[] primeArray = { 61, 67, 71, 73, 79, 83, 89, 97,
			101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
			167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
			239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311,
			313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389,
			397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
			467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563,
			569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641,
			643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
			733 };

	public MyHashTable(int length) {
		super();
		table = new LinkedList[length];
		prime = getPrime();
	}

	public MyHashTable() {
		table = new LinkedList[prime];
	}

	@Override
	public boolean put(Comparable key, Object element) {
		// TODO Auto-generated method stub
		int index = calculateHashFunction((Integer) key);
		HashObject obj = new HashObject((Integer) key, (Integer) element);
		LinkedList<HashObject> list = (LinkedList<HashObject>) table[index];
		if (list == null) {
			list = new LinkedList<HashObject>();
			list.add(obj.clone());
			table[index] = (LinkedList<HashObject>) list;
			return true;
		} else {
			list.add(obj.clone());
			table[index] = (LinkedList<HashObject>) list;
			return true;

		}

	}

	private int getPrime() {
		if (table.length > primeArray[primeArray.length - 1]) {
			return primeArray[primeArray.length - 1];
		}
		return primeArray[getSuitablePrime(primeArray.length / 2)];
	}

	private int getSuitablePrime(int mid) {

		if (primeArray[mid] > table.length) {
			return mid;
		} else if (primeArray[mid] < table.length) {
			return getSuitablePrime((mid + primeArray.length) / 2);
		} else {
			return primeArray[primeArray.length - 1];
		}
	}

	@Override
	public Integer get(Comparable key) {
		int frameNumber = -1;
		int hash = calculateHashFunction((Integer) key);
		LinkedList<HashObject> list = (LinkedList<HashObject>) table[hash];
		HashObject frame = new HashObject();
		if (list != null) {
			Iterator<HashObject> it = list.iterator();
			while (it.hasNext()) {
				frame = it.next();
				if (frame.getPageId() == (Integer) key) {
					frameNumber = frame.getFrameNumber();
				}

			}
		}

		return frameNumber;
	}

	private int calculateHashFunction(int x) {
		return ((a * x + b) % prime) % table.length;

	}

	@Override
	public boolean remove(Comparable key) {
		boolean check = false;
		int frameNumber = -1;
		int hash = calculateHashFunction((Integer) key);
		LinkedList<HashObject> list = (LinkedList<HashObject>) table[hash];
		HashObject frame = new HashObject();
		if (list != null) {
			Iterator<HashObject> it = list.iterator();
			while (it.hasNext()) {
				frame = it.next();
				if (frame.getPageId() == (Integer) key) {
					check = true;
					it.remove();
					break;
				}

			}

		}
		table[hash] = list;
		return check;
	}

	public static void main(String[] args) {
		MyHashTable<Integer> k = new MyHashTable<Integer>(40000);

	}

}
